function gewAabb(min,max)
{
  if(!min)
    min = new gewVec3();
  if(!max)
    max = new gewVec3();
  this.corners = [];
  var c = this.corners;
  c[0] = min.dup();
  c[1] = max.dup();
  c[2] = new gewVec3(min.x, min.y, max.z);
  c[3] = new gewVec3(min.x, max.y, min.z);
  c[4] = new gewVec3(max.x, min.y, min.z);
  c[5] = new gewVec3(max.x, max.y, min.z);
  c[6] = new gewVec3(min.x, max.y, max.z);
  c[7] = new gewVec3(max.x, min.y, max.z);
  this.min = c[0];
  this.max = c[1]; 
  this.center = min.add(max).divScalar(2);
  this.halfSize = max.sub(this.center);
  this.outerPlane = 0; // help VFC faster
}
gewAabb.prototype = {
  getCenter:function(result)
  {
    if(!result)
      result = new gewVec3();
    var c = this.center;
    result.set(c.x,c.y,c.z);
    return result;
  },
  isValid:function()
  {
    var min = this.min;
    var max = this.max;
    if(min.x==max.x&&min.y==max.y&&min.z==max.z)
      return false;
    return true;
  },
  init: function(min,max)
  {
    if(!min)
      min = this.min;
    if(!max)
      max = this.max;
    var c = this.corners;
    var minX = min.x,minY = min.y,minZ = min.z,maxX = max.x,maxY = max.y,maxZ = max.z;
    c[0].x = minX;c[0].y = minY;c[0].z = minZ;
    c[1].x = maxX;c[1].y = maxY;c[1].z = maxZ;
    c[2].x = minX;c[2].y = minY;c[2].z = maxZ;
    c[3].x = minX;c[3].y = maxY;c[3].z = minZ;
    c[4].x = maxX;c[4].y = minY;c[4].z = minZ;
    c[5].x = maxX;c[5].y = maxY;c[5].z = minZ;
    c[6].x = minX;c[6].y = maxY;c[6].z = maxZ;
    c[7].x = maxX;c[7].y = minY;c[7].z = maxZ;
    this.center = min.add(max).divScalar(2);
    this.halfSize = max.sub(this.center);
  },
  repair: function()
  {
    var temp;
    var min = this.min;
    var max = this.max;
    if (min.x > max.x) 
    {
      temp = min.x;
      min.x = max.x;
      max.x = temp;
    }
    if (min.y > max.y) 
    {
      temp = min.y;
      min.y = max.y;
      max.y = temp;
    }
    if (min.z > max.z) 
    {
      temp = min.z;
      min.z = max.z;
      max.z = temp;
    }
    this.init();
  },
  // corner is a array that contain 8 corner(vector )of this aabb
  initFromCorner: function(corner)
  {
    var maxX = -10000;
    var maxY = -10000;
    var maxZ = -10000;
    var minX = 10000;
    var minY = 10000;
    var minZ = 10000;
    //var c = this.corners
    for (var i = 0; i < 8; i++) 
    {
      //c[i] = corner[i];
      var x = corner[i].x;
      var y = corner[i].y;
      var z = corner[i].z;
      if (x > maxX) 
        maxX = x;
      if (y > maxY) 
        maxY = y;
      if (z > maxZ) 
        maxZ = z;
      if (x < minX) 
        minX = x;
      if (y < minY) 
        minY = y;
      if (z < minZ) 
        minZ = z;
    }
    var min = gewRegVec0;
    var max = gewRegVec1;
    min.set(minX,minY,minZ);
    max.set(maxX,maxY,maxZ);
    this.init(min,max);
  },
  dup: function()
  {
    var aabb = new gewAabb(this.min,this.max);
    aabb.outerPlane = this.outerPlane;
    return aabb;
  },
  copyFrom: function(rhs)
  {
    this.init(rhs.min,rhs.max);
    this.outerPlane = rhs.outerPlane;    
  },
  addInternalPoint:function(point)
  {
    this.addInternalPointXYZ(point.x,point.y,point.z);
  },
  addInternalPointXYZ:function(x,y,z)
  {
    var max = this.max;
    var min = this.min;
    var maxx = max.x, maxy = max.y, maxz = max.z;
    var minx = min.x, miny = min.y, minz = min.z;
    if(maxx==0&&maxy==0&&maxz==0&&
       maxx==0&&maxy==0&&maxz==0)
    {
      max.x=x;max.y=y;max.z=z;
      min.x=x;min.y=y;min.z=z;
      return;
    }
    if (x>maxx) 
      max.x = x;
    if (y>maxy) 
      max.y = y;
    if (z>maxz) 
      max.z = z;
    if (x<minx) 
      min.x = x;
    if (y<miny) 
      min.y = y;
    if (z<minz) 
      min.z = z;
  },
  addInternalBox:function(inner_box)
  {
    var min = inner_box.min;
    var max = inner_box.max;
    this.addInternalPointXYZ(min.x,min.y,min.z);
    this.addInternalPointXYZ(max.x,max.y,max.z);
  },
  isContainPoint:function(point)
  {
    var min = this.min;
    var max = this.max;
    var x = point.x;var y=point.y;var z = point.z;
    if( x< min.x || x > max.x ||
        y< min.y || y > max.y ||
        z< min.z || z > max.z)
      return GEW_OUT;
    return GEW_IN;
  },
  // Return GEW_OUT if no collide and GEW_INTERSECT in otherwise
  collisionWithAabb:function(aabb)
  {
    var min1 = this.min;
    var max1 = this.max;
    var min2 = aabb.min;
    var max2 = aabb.max;
    // Use Separating Axis Theorem
    // X axis
    if( min1.x > max2.x ||
        max1.x < min2.x)
        return GEW_OUT;
    // Y axis
    if( min1.y > max2.y ||
        max1.y < min2.y)
        return GEW_OUT;
    // Z axis
    if( min1.z > max2.z ||
        max1.z < min2.z)
        return GEW_OUT;
    return GEW_INTERSECT;   
  },
  // This test algorithm is taken from : http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/tribox3.txt
  // Return GEW_OUT if no collide and GEW_INTERSECT in otherwise
  collisionWithTriangle:function(triangle)
  {
    //use separating axis theorem to test overlap between triangle and box
    //need to test for overlap in these directions: 
    //    1) the {x,y,z}-directions (actually, since we use the AABB of the triangle 
    //       we do not even need to test these) 
    //    2) normal of the triangle 
    //    3) crossproduct(edge from tri, {x,y,z}-directin) 
    //       this gives 3x3=9 more tests 

    var v0 = gewRegVec0;
    var v1 = gewRegVec1;
    var v2 = gewRegVec2;
    
    var e0 = gewRegVec3;
    var e1 = gewRegVec4;
    var e2 = gewRegVec5;
    
    var normal = gewRegVec6;
    var min,max,p0,p1,p2,rad,fex,fey,fez;
    
    var center = this.center;
    var boxhalfsize = this.halfSize;
    // Move the triangle vertex so that the box center is (0,0,0)
    triangle.v0.sub(center,v0); // v0 =  triangle.v0-center;
    triangle.v1.sub(center,v1);
    triangle.v2.sub(center,v2);
    // Compute triangle's edges
    v1.sub(v0,e0);
    v2.sub(v1,e1);
    v0.sub(v2,e2);
    // Test 3) first
    fex = Math.abs(e0.x);
    fey = Math.abs(e0.y);
    fez = Math.abs(e0.z);
    // AXISTEST_X01(e0[Z], e0[Y], fez, fey);
    var a = e0.z;
    var b = e0.y;
    var fa = fez;
    var fb = fey;
    p0 = a*v0.y - b*v0.z;  
    p2 = a*v2.y - b*v2.z;           
    if(p0<p2) 
      {min=p0; max=p2;} 
    else 
      {min=p2; max=p0;} 
    rad = fa * boxhalfsize.y + fb * boxhalfsize.z; 
    if(min>rad || max<-rad) 
      return GEW_OUT;
    // AXISTEST_Y02(e0[Z], e0[X], fez, fex);
    b=e0.x;fb=fex;
    p0 = -a*v0.x + b*v0.z;
    p2 = -a*v2.x + b*v2.z;     
    if(p0<p2) 
      {min=p0; max=p2;} 
    else 
      {min=p2; max=p0;} 
    rad = fa * boxhalfsize.x + fb * boxhalfsize.z;  
    if(min>rad || max<-rad) 
      return GEW_OUT;
    // AXISTEST_Z12(e0[Y], e0[X], fey, fex);
    a = e0.y;b=e0.x;fa=fey;fb=fex;
    p1 = a*v1.x - b*v1.y;
    p2 = a*v2.x - b*v2.y; 
    if(p2<p1) 
      {min=p2; max=p1;} 
    else 
      {min=p1; max=p2;}
    rad = fa * boxhalfsize.x + fb * boxhalfsize.y;
    if(min>rad || max<-rad) 
      return GEW_OUT;
    
    fex = Math.abs(e1.x);
    fey = Math.abs(e1.y);
    fez = Math.abs(e1.z);
    // AXISTEST_X01(e1[Z], e1[Y], fez, fey);
    a = e1.z;b=e1.y;fa=fez;fb=fey;
    var a = e0.z;
    var b = e0.y;
    var fa = fez;
    var fb = fey;
    p0 = a*v0.y - b*v0.z;  
    p2 = a*v2.y - b*v2.z;           
    if(p0<p2) 
      {min=p0; max=p2;} 
    else 
      {min=p2; max=p0;} 
    rad = fa * boxhalfsize.y + fb * boxhalfsize.z; 
    if(min>rad || max<-rad) 
      return GEW_OUT;
    // AXISTEST_Y02(e1[Z], e1[X], fez, fex);
    a=e1.z;b=e1.x;fa=fez;fb=fex;
    b=e0.x;fb=fex;
    p0 = -a*v0.x + b*v0.z;
    p2 = -a*v2.x + b*v2.z;     
    if(p0<p2) 
      {min=p0; max=p2;} 
    else 
      {min=p2; max=p0;} 
    rad = fa * boxhalfsize.x + fb * boxhalfsize.z;  
    if(min>rad || max<-rad) 
      return GEW_OUT;
    // AXISTEST_Z0(e1[Y], e1[X], fey, fex);
    a = e1.y;b=e1.x;fa=fey;fb=fex;
    p0 = a*v0.x - b*v0.y;
    p1 = a*v1.x - b*v1.y;  
    if(p0<p1) 
      {min=p0; max=p1;} 
    else 
      {min=p1; max=p0;}
    rad = fa * boxhalfsize.x + fb * boxhalfsize.y;
    if(min>rad || max<-rad) 
      return GEW_OUT;

    fex = Math.abs(e2.x);
    fey = Math.abs(e2.y);
    fez = Math.abs(e2.z);
    // AXISTEST_X2(e2[Z], e2[Y], fez, fey);
    a=e2.z;b=e2.y;fa=fez;fb=fey;
    p0 = a*v0.y - b*v0.z; 
    p1 = a*v1.y - b*v1.z; 
    if(p0<p1) 
      {min=p0; max=p1;} 
    else 
      {min=p1; max=p0;}
    rad = fa * boxhalfsize.y + fb * boxhalfsize.z; 
    if(min>rad || max<-rad) 
      return GEW_OUT;
    // AXISTEST_Y1(e2[Z], e2[X], fez, fex);
    a=e2.z;b=e2.x;fa=fez;fb=fex;
    p0 = -a*v0.x + b*v0.z; 
    p1 = -a*v1.x + b*v1.z; 
    if(p0<p1) 
      {min=p0; max=p1;} 
    else 
      {min=p1; max=p0;} 
    rad = fa * boxhalfsize.x + fb * boxhalfsize.z;
    if(min>rad || max<-rad) 
      return GEW_OUT;
    // AXISTEST_Z12(e2[Y], e2[X], fey, fex);
    a = e2.y;b=e2.x;fa=fey;fb=fex;
    p1 = a*v1.x - b*v1.y;
    p2 = a*v2.x - b*v2.y; 
    if(p2<p1) 
      {min=p2; max=p1;} 
    else 
      {min=p1; max=p2;}
    rad = fa * boxhalfsize.x + fb * boxhalfsize.y;
    if(min>rad || max<-rad) 
      return GEW_OUT;
    
    // Test 1)
    /* test in X-direction */
    max = Math.max(v0.x,v1.x,v2.x);
    min = Math.min(v0.x,v1.x,v2.x);
    if(min>boxhalfsize.x || max<-boxhalfsize.x) 
      return GEW_OUT;
    /* test in Y-direction */    
    max = Math.max(v0.y,v1.y,v2.y);
    min = Math.min(v0.y,v1.y,v2.y);
    if(min>boxhalfsize.y || max<-boxhalfsize.y) 
      return GEW_OUT;  
    /* test in Z-direction */    
    max = Math.max(v0.z,v1.z,v2.z);
    min = Math.min(v0.z,v1.z,v2.z);
    if(min>boxhalfsize.z || max<-boxhalfsize.z) 
      return GEW_OUT; 
    
    // Test 2)
    e0.cross(e1,normal);
    
    var vert = v0;
    var maxbox = boxhalfsize; 
    var  q;
    var vmin = gewRegVec7;
    var vmax = gewRegVec8;
    var v;
    v=vert.x;        
    if(normal.x>0.0)
    {
      vmin.x=-maxbox.x - v; 
      vmax.x= maxbox.x - v; 
    }
    else
    {
      vmin.x= maxbox.x - v; 
      vmax.x=-maxbox.x - v; 
    }
    v=vert.y;        
    if(normal.y>0.0)
    {
      vmin.y=-maxbox.y - v; 
      vmax.y= maxbox.y - v; 
    }
    else
    {
      vmin.y= maxbox.y - v; 
      vmax.y=-maxbox.y - v; 
    }
    v=vert.z;        
    if(normal.z>0.0)
    {
      vmin.z=-maxbox.z - v; 
      vmax.z= maxbox.z - v; 
    }
    else
    {
      vmin.z= maxbox.z - v; 
      vmax.z=-maxbox.z - v; 
    }    
    if( normal.dot(vmin)>0.0) 
      return GEW_OUT; 
    if( normal.dot(vmax)>=0.0) 
      return GEW_INTERSECT;  
    return GEW_OUT;   
  },
  collisionWithMesh:function(meshVertices,meshIndices,outTriangles)
  {
    var triangle = new gewTriangle();
    var triangle_num = meshIndices.length/3;
    var isIntersect = false;
    for(var i=0;i<triangle_num;i++)
    {
      var v0offset = meshIndices[i*3] *3;
      var v1offset = meshIndices[i*3+1]*3;
      var v2offset = meshIndices[i*3+2]*3;
      triangle.v0.set( meshVertices[v0offset],meshVertices[v0offset+1],meshVertices[v0offset+2] );
      triangle.v1.set( meshVertices[v1offset],meshVertices[v1offset+1],meshVertices[v1offset+2] );
      triangle.v2.set( meshVertices[v2offset],meshVertices[v2offset+1],meshVertices[v2offset+2] );
      
      var isCollision = this.collisionWithTriangle(triangle);
      if(isCollision==GEW_INTERSECT)
      {
        var collideTri = new gewTriangle();
        collideTri.v0.set( meshVertices[v0offset],meshVertices[v0offset+1],meshVertices[v0offset+2] );
        collideTri.v1.set( meshVertices[v1offset],meshVertices[v1offset+1],meshVertices[v1offset+2] );
        collideTri.v2.set( meshVertices[v2offset],meshVertices[v2offset+1],meshVertices[v2offset+2] );
        isIntersect = true;
        outTriangles.push(collideTri);
      }
    }
    if(isIntersect)
    {
      return GEW_INTERSECT;
    }
    return GEW_OUT;
  }
}
